﻿using System;
using System.Collections.Generic;
using System.Text;
using ChaosEngine.EngineCore;
using ChaosEngine.GPU.Core;

using SlimDX;
using SlimDX.Windows;
using SlimDX.DXGI;
using SlimDX.Direct3D11;
using DX = SlimDX.Direct3D11;

namespace ChaosEngine.GPU.API.DirectX
{
    public class GCDX11 : vGPUCore
    {
        internal RenderForm Form;
        internal SwapChain Chain;
        internal SlimDX.Direct3D11.Device Dev;
        internal SlimDX.DXGI.Factory XFactory;
        internal Texture2D BufBack;
        internal RenderTargetView RTView;
        public GCDX11() : base("Anthony Wells","Pre-Alpha","DX11"){

        }
        public override bool InitGpu()
        {
            return true;
        }
        public override vGPUCore SpawnInstance()
        {
            return new GCDX11();
        }
        public override bool EmbedCore(System.Windows.Forms.Control surface, string app)
        {
            var Form = surface;
            var desc = new SwapChainDescription()
            {
                BufferCount = 1,
                ModeDescription = new ModeDescription(Form.ClientSize.Width, Form.ClientSize.Height, new Rational(60, 1), Format.R8G8B8A8_UNorm),
                IsWindowed = true,
                OutputHandle = surface.Handle,
                SampleDescription = new SampleDescription(1, 0),
                SwapEffect = SwapEffect.Discard,
                Usage = Usage.RenderTargetOutput
            };


            FeatureLevel[] fl = new FeatureLevel[1];
            fl[0] = FeatureLevel.Level_10_0;

            //            Device.CreateWithSwapChain(null, DriverType.Hardware, DeviceCreationFlags.Debug, desc, out device, out swapChain);
            SlimDX.Direct3D11.Device.CreateWithSwapChain(null, DriverType.Hardware, DeviceCreationFlags.Debug, fl, desc, out Dev, out Chain);

            //Stops Alt+enter from causing fullscreen skrewiness.
            XFactory = Chain.GetParent<SlimDX.DXGI.Factory>();
            XFactory.SetWindowAssociation(Form.Handle, WindowAssociationFlags.IgnoreAll);

            BufBack = Texture2D.FromSwapChain<Texture2D>(Chain, 0);
            RTView = new RenderTargetView(Dev, BufBack);

            Dev.ImmediateContext.OutputMerger.SetTargets(RTView);
            Dev.ImmediateContext.Rasterizer.SetViewports(new Viewport(0, 0, Form.ClientSize.Width, Form.ClientSize.Height, 0.0f, 1.0f));

            return true;
        }
        public override bool CreateForm(int x, int y, int w, int h, bool full, string app)
        {
            Form = new RenderForm(app + " - Made with Vivid3D(OSCE) - ALPHA SOFTWARE -");
            var desc = new SwapChainDescription()
            {
                BufferCount = 1,
                ModeDescription = new ModeDescription(Form.ClientSize.Width, Form.ClientSize.Height, new Rational(60, 1), Format.R8G8B8A8_UNorm),
                IsWindowed = full ? false : true,
                OutputHandle = Form.Handle,
                SampleDescription = new SampleDescription(1, 0),
                SwapEffect = SwapEffect.Discard,
                Usage = Usage.RenderTargetOutput
            };


            FeatureLevel[] fl = new FeatureLevel[1];
            fl[0] = FeatureLevel.Level_10_0;

            //            Device.CreateWithSwapChain(null, DriverType.Hardware, DeviceCreationFlags.Debug, desc, out device, out swapChain);
            SlimDX.Direct3D11.Device.CreateWithSwapChain(null, DriverType.Hardware, DeviceCreationFlags.Debug, fl,desc, out Dev, out Chain);

            //Stops Alt+enter from causing fullscreen skrewiness.
            XFactory = Chain.GetParent<SlimDX.DXGI.Factory>();
            XFactory.SetWindowAssociation(Form.Handle, WindowAssociationFlags.IgnoreAll);

            BufBack = Texture2D.FromSwapChain<Texture2D>(Chain, 0);
            RTView = new RenderTargetView(Dev, BufBack);
            
            Dev.ImmediateContext.OutputMerger.SetTargets(RTView);
            Dev.ImmediateContext.Rasterizer.SetViewports(new Viewport(0, 0, Form.ClientSize.Width, Form.ClientSize.Height, 0.0f, 1.0f));

            return true;
        }
        public override void EmbedBeginDraw()
        {

            Dev.ImmediateContext.ClearRenderTargetView(RTView, new Color4(ClearColor));

          
        }

        public override void EmbedEndDraw(){

            Chain.Present(0, PresentFlags.None);

        }

        public override int RunCore(EngineCore.VividApp app)
        {
            app.InitApp();

            MessagePump.Run(Form, () =>
            {

                for (int i = 0; i < UpdateCycles; i++)
                {
                    app.UpdateApp();
                }

                Dev.ImmediateContext.ClearRenderTargetView(RTView, new Color4(ClearColor));

                app.DrawApp();

                Chain.Present(0, PresentFlags.None);
            });
            return 1;
        }
        public override vDataBuffer CreateVertexBuffer(float[] pos, float[] uv, float[] norm)
        {
            var r = new vDX11DataBuffer();

            /*
            f.Layout = new InputLayout(Dev, pass.Description.Signature, new[] {
                new InputElement("POSITION", 0, Format.R32G32B32A32_Float, 0, 0),
                new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 16, 0) 
            });
            */
            int ni = 0;
            r.Stream = new DataStream(pos.Length * 4 + uv.Length * 4 + norm.Length * 4, true, true);
            for(int v=0;v<pos.Length;v=v+3)
            {
                r.Stream.Write<float>(pos[v]);
                r.Stream.Write<float>(uv[v]);
                r.Stream.Write<float>(norm[ni]);
                r.Stream.Write<float>(norm[ni = 1]);
                r.Stream.Write<float>(norm[ni + 2]);
                r.Stream.Write<float>(pos[v + 1]);
                r.Stream.Write<float>(uv[v + 1]);
                r.Stream.Write<float>(norm[ni + 3]);
                r.Stream.Write<float>(norm[ni + 4]);
                r.Stream.Write<float>(norm[ni + 5]);
                r.Stream.Write<float>(pos[v + 2]);
                r.Stream.Write<float>(uv[v + 2]);
                r.Stream.Write<float>(norm[ni + 6]);
                r.Stream.Write<float>(norm[ni + 7]);
                r.Stream.Write<float>(norm[ni + 8]);
                ni = ni + 9;
            }
            r.Stream.Position = 0;

            var vertices = new SlimDX.Direct3D11.Buffer(Dev, r.Stream, new BufferDescription()
            {
                BindFlags = BindFlags.VertexBuffer,
                CpuAccessFlags = CpuAccessFlags.None,
                OptionFlags = ResourceOptionFlags.None,
                SizeInBytes = (int)r.Stream.Length,
                Usage = ResourceUsage.Default
            });
            r.Stream.Dispose();
            r.Stream = null;

            r.Data = vertices;

            return r;

        }

        public override vDataBuffer CreateIndexBuffer(int[] indices)
        {
            var r = new vDX11DataBuffer();

            /*
            f.Layout = new InputLayout(Dev, pass.Description.Signature, new[] {
                new InputElement("POSITION", 0, Format.R32G32B32A32_Float, 0, 0),
                new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 16, 0) 
            });
            */
 
            r.Stream = new DataStream(indices.Length * 4, true, true);
            r.Stream.WriteRange<int>(indices);
            r.Stream.Position = 0;

            var indices2 = new SlimDX.Direct3D11.Buffer(Dev, r.Stream, new BufferDescription()
            {
                BindFlags = BindFlags.IndexBuffer,
                CpuAccessFlags = CpuAccessFlags.None,
                OptionFlags = ResourceOptionFlags.None,
                SizeInBytes = (int)r.Stream.Length,
                Usage = ResourceUsage.Default
            });
            r.Stream.Dispose();
            r.Stream = null;

            r.Data = indices2;

            return r;
        }

        public override vEffect EffectFromFile(string addr)
        {
            throw new NotImplementedException();
        }
        public override void EffectSetFloat(vEffect fx, string name, float v) { }
        public override void EffectSetMatrix(vEffect fx, string name, Matrix v) { }

        public override  void EffectSetVector3(vEffect fx, string name, Vector3 v) { }

        public override  void EffectSetVector4(vEffect fx, string name, Vector4 v) { }

        public override void DrawGeo(vDataBuffer vertices, vDataBuffer indices, vEffect fx, int tech, int pass){}
    }
    public class vDX11Effect : vEffect
    {
        public SlimDX.Direct3D11.Effect FX { get; set; }
   
    

    }
    public class vDX11DataBuffer : vDataBuffer
    {
        public SlimDX.Direct3D11.Buffer Data { get; set; }
        public DataStream Stream { get; set; }
        public InputLayout Layout { get; set; }
        public override void CreateBuffer()
        {
                    }
        public override void SetData(float[] data)
        {

         }

        public override void FreeData()
        {

            if (Stream != null)
            {
            
                Stream.Dispose();
                Stream = null;
            
            }

            if(Data!=null){
            
                Data.Dispose();
                Data = null;

            }

            
        }

    }
}
